package com.jspgou.cms.dao.impl;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexWriter;
import org.hibernate.CacheMode;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.springframework.stereotype.Repository;

import com.jspgou.cms.dao.ProductDao;
import com.jspgou.cms.entity.Product;
import com.jspgou.cms.entity.ProductTag;
import com.jspgou.cms.lucene.LuceneProduct;
import com.jspgou.common.hibernate3.Finder;
import com.jspgou.common.hibernate3.HibernateBaseDao;
import com.jspgou.common.page.Pagination;

@Repository
public class ProductDaoImpl extends HibernateBaseDao<Product, Long> implements
		ProductDao {
	public Pagination getPageByCategory(Long ctgId,Long storeId,String productName,String brandName,
			Long source,Boolean Ontheshelf,Boolean Whetherban,
			Boolean Whetherpresale,Long typeId,Double startSalePrice,Double endSalePrice,
			Integer startStock,Integer endStock,int pageNo, int pageSize, boolean cacheable) {
		Finder f = getFinderForCategory(ctgId,storeId, productName,brandName,source,Ontheshelf,Whetherban,
				Whetherpresale,typeId,startSalePrice,endSalePrice,
				startStock,endStock,cacheable);
		return find(f, pageNo, pageSize);
	}
	public Pagination getPageByCategoryChannel(Long storeId,Long brandRadio,String brandId,Long ctgId,
			Long storeCategoryId,String[] names,String[] values,int orderBy,Double startPrice,Double endPrice,
			int pageNo, int pageSize, boolean cacheable) {
		Finder f = getFinderForCategoryChannel(storeId,brandRadio,brandId, ctgId, storeCategoryId,
				names,values,orderBy,startPrice,endPrice,cacheable);	
		return find(f, pageNo, pageSize);
	}
	
	@SuppressWarnings("unchecked")//返回历史记录
	public List<Product> getHistoryProduct(HashSet<Long> set,Integer count){
		if(set.size()>0){
			return this.getSession().createQuery("from Product bean where bean.id in (:ids)")
			.setParameterList("ids", set).setMaxResults(count).list();
		}else{
			return new ArrayList();
		}
	}
	
	@SuppressWarnings("unchecked")
	public List<Product> getList(Long storeId,Long typeId,Long brandId,String productName,boolean cacheable) {
		Finder f = Finder.create("from Product bean where 1=1");
		if (storeId != null) {
			f.append(" and bean.store.id=:storeId");
			f.setParam("storeId", storeId);
		}else{
			f.append(" and bean.store.id is null");
		}
		if (typeId != null) {
			f.append(" and bean.type.id=:typeId");
			f.setParam("typeId", typeId);
		}
		if (brandId != null) {
			f.append(" and bean.brand.id=:brandId");
			f.setParam("brandId",brandId);
		}
		if (!StringUtils.isBlank(productName)) {
			f.append(" and bean.name like:productName");
			f.setParam("productName", "%"+productName+"%");
		}
		f.setCacheable(cacheable);
		return find(f);
	}

	public Pagination getPageByWebsite(Long webId,Long storeId, String productName,String brandName,
			Long storeCategoryId,Long source,Boolean Ontheshelf,Boolean Whetherban,
			Boolean Whetherpresale,Long typeId,Double startSalePrice,Double endSalePrice,
			Integer startStock,Integer endStock, int pageNo, int pageSize, boolean cacheable) {
		Finder f = getFinderForWebsite(webId,storeId,productName,brandName,storeCategoryId,source,Ontheshelf,Whetherban,
				Whetherpresale,typeId,startSalePrice,endSalePrice,
				startStock,endStock,cacheable);
		return find(f, pageNo, pageSize);
	}

	public Pagination getPageByTag(Long storeId,Long tagId, Long ctgId, Long storeCategoryId,int pageNo, int pageSize, boolean cacheable) {
		Finder f = getFinderForTag(storeId,ctgId, tagId,storeCategoryId,cacheable);
		return find(f, pageNo, pageSize);
	}

	@SuppressWarnings("unchecked")
	public List<Product> getListByCategory(Long ctgId,  int firstResult, int maxResults,
			boolean cacheable) {
		Finder f = getFinderForCategory(ctgId, null,null,null,null,
				null,null,null,null,null,null,null,null,cacheable);
		f.setFirstResult(firstResult);
		f.setMaxResults(maxResults);
		return find(f);
	}
	
	@SuppressWarnings("unchecked")
	public List<Product> getListByStore(Long storeId, 
			int firstResult, int maxResults,boolean cacheable) {
		Finder f = getFinderForStore(storeId, null,null,null,null,null,null,
				null,null,cacheable);
		f.setFirstResult(firstResult);
		f.setMaxResults(maxResults);
		return find(f);
	}

	@SuppressWarnings("unchecked")
	public List<Product> getListByWebsite(Long webId, int firstResult, int maxResults,
			boolean cacheable) {
		Finder f = getFinderForWebsite(webId,null,null,null,null,null,
				null,null,null,null,null,null,null,null,cacheable);
		f.setFirstResult(firstResult);
		f.setMaxResults(maxResults);
		return find(f);                                                                                                                                                    
	}	
	
	@SuppressWarnings("unchecked")
	public List<Product> getListByWebsite1(Long webId,  int firstResult, int maxResults,
			boolean cacheable) {
		Finder f = getFinderForWebsite1(webId,cacheable);
		f.setFirstResult(firstResult);
		f.setMaxResults(maxResults);
		return find(f);
	}

	@SuppressWarnings("unchecked")
	public List<Product> getListByTag(Long tagId, Long ctgId,
			 int firstResult,
			int maxResults, boolean cacheable) {
		Finder f = getFinderForTag(null,tagId, ctgId,null, 
				cacheable);
		f.setFirstResult(firstResult);
		f.setMaxResults(maxResults);
		return find(f);
	}
	private Finder getFinderForCategory(Long ctgId,Long storeId, String productName,String brandName,
			Long source,Boolean Ontheshelf,Boolean Whetherban,
			Boolean Whetherpresale,Long typeId,Double startSalePrice,Double endSalePrice,
			Integer startStock,Integer endStock, boolean cacheable) {
		Finder f = Finder.create("select bean from Product bean");
		f.append(" inner join bean.category node,Category parent");
		f.append(" where node.lft between parent.lft and parent.rgt");
		f.append(" and parent.id=:ctgId");
		if (!StringUtils.isBlank(productName)) {
			f.append(" and bean.name like:productName");
			f.setParam("productName", "%"+productName+"%");
		}
		if (!StringUtils.isBlank(brandName)) {
			f.append(" and bean.brand.name like:brandName");
			f.setParam("brandName", "%"+brandName+"%");
		}
		//判断商品来源
		if(source!=null){
			if(source==0){
				f.append(" and bean.store is null");
			}else if(source==1){
				f.append(" and bean.store is not null");
			}
		}
		//判断是否上架
		if (Ontheshelf != null) {
			f.append(" and bean.onSale=:isOnSale");
			f.setParam("isOnSale", Ontheshelf);
		}
		//判断是否禁售
		if(Whetherban!=null){
			f.append(" and bean.prohibit=:Whetherban");
			f.setParam("Whetherban", Whetherban);
		}
		//判断是否预售
		if(Whetherpresale!=null){
			f.append(" and bean.yushou=:Whetherpresale");
			f.setParam("Whetherpresale", Whetherpresale);
		}
		if (typeId != null) {
			f.append(" and bean.type.id=:typeId");
			f.setParam("typeId", typeId);
		}
		if (storeId != null) {
			f.append(" and bean.store.id=:storeId");
			f.setParam("storeId", storeId);
		}
		if (startSalePrice != null) {
			f.append(" and bean.salePrice>:startSalePrice");
			f.setParam("startSalePrice", startSalePrice);
		}
		if (endSalePrice != null) {
			f.append(" and bean.salePrice<:endSalePrice");
			f.setParam("endSalePrice", endSalePrice);
		}
		if (startStock != null) {
			f.append(" and bean.stockCount>:startStock");
			f.setParam("startStock", startStock);
		}
		if (endStock != null) {
			f.append(" and bean.stockCount<:endStock");
			f.setParam("endStock", endStock);
		}
		f.append(" order by bean.id desc");
		f.setParam("ctgId", ctgId);
		f.setCacheable(cacheable);
		return f;
	}
	
	private Finder getFinderForStore(Long storeId, String productName,String brandName,
			Boolean isOnSale,Long typeId,BigDecimal startSalePrice,BigDecimal endSalePrice,
			Integer startStock,Integer endStock, boolean cacheable) {
		Finder f = Finder.create("select bean from Product bean where 1=1");
		if (!StringUtils.isBlank(productName)) {
			f.append(" and bean.name like:productName");
			f.setParam("productName", "%"+productName+"%");
		}
		if (!StringUtils.isBlank(brandName)) {
			f.append(" and bean.brand.name like:brandName");
			f.setParam("brandName", "%"+brandName+"%");
		}
		if (isOnSale != null) {
			f.append(" and bean.onSale=:isOnSale");
			f.setParam("isOnSale", isOnSale);
		}
		if (typeId != null) {
			f.append(" and bean.type.id=:typeId");
			f.setParam("typeId", typeId);
		}
		if (storeId != null) {
			f.append(" and bean.store.id=:storeId");
			f.setParam("storeId", storeId);
		}
		if (startSalePrice != null) {
			f.append(" and bean.salePrice>:startSalePrice");
			f.setParam("startSalePrice", startSalePrice);
		}
		if (endSalePrice != null) {
			f.append(" and bean.salePrice<:endSalePrice");
			f.setParam("endSalePrice", endSalePrice);
		}
		if (startStock != null) {
			f.append(" and bean.stockCount>:startStock");
			f.setParam("startStock", startStock);
		}
		if (endStock != null) {
			f.append(" and bean.stockCount<:endStock");
			f.setParam("endStock", endStock);
		}
		f.append(" order by bean.id desc");
		f.setCacheable(cacheable);
		return f;
	}

	private Finder getFinderForCategoryChannel(Long storeId,Long brandRadio,String brandId,Long ctgId,
			Long storeCategoryId,String[] names,String[] values,
			int orderBy,Double startPrice,Double endPrice,boolean cacheable) {
		Finder f = Finder.create("select distinct bean from Product bean");
		f.append(" join bean.category node,Category parent");
		if(storeCategoryId!=null){
			f.append(" inner join bean.storeCategorys storeCategory with storeCategory.id=:storeCategoryId");
		}
		//商品属性多选的情况下
		String[] exendeds = null;
		if(names!=null){
			exendeds=new String[names.length];
	    	for(int i=0,j=names.length;i<j;i++){
	    		String exended="exended"+i;
	    		exendeds[i]=exended;
	    		f.append(" inner join bean.exendeds "+exended);
	    	}
		}
		if(ctgId!=null){
			f.append(" where node.lft between parent.lft and parent.rgt");
			f.append(" and parent.id=:ctgId");
			f.setParam("ctgId", ctgId);
		}else {
			f.append(" where 1=1 ");
		}
		if(storeCategoryId!=null){
			f.setParam("storeCategoryId", storeCategoryId);
		}
		//品牌单选
		if(brandRadio!=null){
			f.append(" and bean.brand.id=:id");
			f.setParam("id", brandRadio);
		}
		//品牌多选
		if(brandId!=null&&!brandId.equals("")){//品牌
			f.append(" and bean.brand.id in("+brandId+")");
//			f.setParam("brandId", brandId);
		}
		if(storeId!=null){//店铺
			f.append(" and bean.store.id=:storeId");
			f.setParam("storeId", storeId);
		}
		//商品属性单选的情况下
		if(names!=null){
	    	for(int i=0;i<names.length;i++){
	    	  String an="attr_name"+i;
	    	  String av="attr_value"+i;
			  if(!values[i].equals("0")){
			   f.append(" and "+exendeds[i]+".name=:"+an).setParam(an, names[i]);
		   	   f.append(" and "+exendeds[i]+".value in(:"+av+")").setParamList(av,values[i].replaceAll("&", ",").split(","));
		 	  }
		  }
		}
		if(startPrice>0){
			f.append(" and bean.salePrice>=:startPrice");
			f.setParam("startPrice", startPrice);
		}
		if(endPrice>0){
			f.append(" and bean.salePrice<=:endPrice");
			f.setParam("endPrice", endPrice);
		}	
		appendOrder(f, orderBy);
		f.setCacheable(cacheable);
		return f;
	}
	
	private void appendOrder(Finder f, int orderBy) {
		switch (orderBy) {
		case 1:
			// ID升序
			f.append(" order by bean.id asc");
			break;
		case 2:
			// 上架时间降序
			f.append(" order by bean.createTime desc");
			break;
		case 3:
			// 上架时间升序
			f.append(" order by bean.createTime asc");
			break;
		case 4:
			//销售量降序、发布时间降序
			f.append(" order by bean.saleCount desc, bean.createTime desc");
			break;
		case 5:
			// 销售量降序、发布时间升序
			f.append(" order by bean.saleCount desc, bean.createTime asc");
			break;
		case 6:
			// 销售价降序
			f.append(" order by bean.salePrice desc, bean.id desc");
			break;
		case 7:
			// 销售价升序
			f.append(" order by bean.salePrice asc,bean.id desc");
			f.append(", bean.id desc");
			break;
		default:
			// 默认： ID降序
			f.append(" order by bean.id desc");
		}
	}
	
	private Finder getFinderForWebsite(Long webId,Long storeId, String productName,String brandName,
			Long storeCategoryId,Long source,Boolean Ontheshelf,Boolean Whetherban,
			Boolean Whetherpresale,Long typeId,Double startSalePrice,Double endSalePrice,
			Integer startStock,Integer endStock,boolean cacheable) {
		Finder f = Finder.create("select bean from Product bean");
		if(storeCategoryId!=null){
			f.append(" inner join bean.storeCategorys storeCategory with storeCategory.id=:storeCategoryId");
		}
		f.append(" where bean.website.id=:webId");
		if(storeCategoryId!=null){
			f.setParam("storeCategoryId", storeCategoryId);
		}
		if (!StringUtils.isBlank(productName)) {
			f.append(" and bean.name like:productName");
			f.setParam("productName", "%"+productName+"%");
		}
		if (!StringUtils.isBlank(brandName)) {
			f.append(" and bean.brand.name like:brandName");
			f.setParam("brandName", "%"+brandName+"%");
		}
		if (storeId != null) {
			f.append(" and bean.store.id=:storeId");
			f.setParam("storeId", storeId);
		}
		//判断商品来源
		if(source!=null){
			if(source==0){
				f.append(" and bean.store is null");
			}else if(source==1){
				f.append(" and bean.store is not null");
			}
		}
		//判断是否上架
		if (Ontheshelf != null) {
			f.append(" and bean.onSale=:isOnSale");
			f.setParam("isOnSale", Ontheshelf);
		}
		//判断是否禁售
		if(Whetherban!=null){
			f.append(" and bean.prohibit=:Whetherban");
			f.setParam("Whetherban", Whetherban);
		}
		//判断是否预售
		if(Whetherpresale!=null){
			f.append(" and bean.yushou=:Whetherpresale");
			f.setParam("Whetherpresale", Whetherpresale);
		}
		if (typeId != null) {
			f.append(" and bean.type.id=:typeId");
			f.setParam("typeId", typeId);
		}
		if (startSalePrice != null) {
			f.append(" and bean.salePrice>:startSalePrice");
			f.setParam("startSalePrice", startSalePrice);
		}
		if (endSalePrice != null) {
			f.append(" and bean.salePrice<:endSalePrice");
			f.setParam("endSalePrice", endSalePrice);
		}
		if (startStock != null) {
			f.append(" and bean.stockCount>:startStock");
			f.setParam("startStock", startStock);
		}
		if (endStock != null) {
			f.append(" and bean.stockCount<:endStock");
			f.setParam("endStock", endStock);
		}
		f.append(" order by bean.id desc");
		f.setParam("webId", webId);
		f.setCacheable(cacheable);
		return f;
	}
	
	private Finder getFinderForWebsite1(Long webId, boolean cacheable) {
		Finder f = Finder.create("from Product bean");
		f.append(" where bean.website.id=:webId");
		f.append(" order by bean.id desc");
		f.setParam("webId", webId);
		f.setCacheable(cacheable);
		return f;
	}
   //商品标签:tagId,产品类别：ctgid
	private Finder getFinderForTag(Long storeId,Long tagId, Long ctgId,Long storeCategoryId, boolean cacheable) {
		Finder f = Finder.create("select bean from Product bean");
		if(tagId!=null){
			f.append(" inner join bean.tags tag with tag.id=:tagId");
		}
		if(storeCategoryId!=null){
			f.append(" inner join bean.storeCategorys storeCategory with storeCategory.id=:storeCategoryId");
		}
		
		f.append(" where 1=1");
		if(tagId!=null){
			f.setParam("tagId", tagId);
		}
		if(storeCategoryId!=null){
			f.setParam("storeCategoryId", storeCategoryId);
		}
		if (ctgId != null) {
			f.append(" and bean.category.id=:ctgId");
			f.setParam("ctgId", ctgId);
		}
		if (storeId != null) {
			f.append(" and bean.store.id=:storeId");
			f.setParam("storeId", storeId);
		}
	
		f.append(" order by bean.id desc");
		f.setCacheable(cacheable);
		return f;
	}

	public int luceneWriteIndex(IndexWriter writer, Long webId, Date start,
			Date end) throws CorruptIndexException, IOException {
		Session session = getSession();
		Finder f = Finder.create("from Product bean where 1=1");
		if (webId != null) {
			f.append(" and bean.website.id=:webId");
			f.setParam("webId", webId);
		}
		if (start != null) {
			f.append(" and bean.createTime >= :start");
			f.setParam("start", start);
		}
		if (end != null) {
			f.append(" and bean.createTime >= :end");
			f.setParam("end", end);
		}

		ScrollableResults products = f.createQuery(session).setCacheMode(
				CacheMode.IGNORE).scroll(ScrollMode.FORWARD_ONLY);
		Product product;
		int count = 0;
		while (products.next()) {
			product = (Product) products.get(0);
			writer.addDocument(LuceneProduct.createDocument(product));
			if (++count % 20 == 0) {
				session.clear();
			}
		}
		return count;
	}

	public int deleteTagAssociation(ProductTag[] tags) {
		Long[] tagIds = new Long[tags.length];
		for (int i = 0, len = tags.length; i < len; i++) {
			tagIds[i] = tags[i].getId();
		}
		Session session = getSession();
		String hql = "from Product bean inner join bean.tags tag where tag.id in (:tagIds)";
		ScrollableResults products = session.createQuery(hql).setParameterList(
				"tagIds", tagIds).setCacheMode(CacheMode.IGNORE).scroll(
				ScrollMode.FORWARD_ONLY);
		int count = 0;
		while (products.next()) {
			Product product = (Product) products.get(0);
			product.getTags().removeAll(Arrays.asList(tags));
			if (++count % 20 == 0) {
				session.flush();
				session.clear();
			}
		}
		return count;
	}
	
	@SuppressWarnings("unchecked")
	public List<Product> getLimitProduct(Long id){
		String hql="select bean from Product bean join bean.productExt ext where ext.islimitTime=true";
		if(id!=null){
			hql+=" and bean.id=:id";
			return this.getSession().createQuery(hql).list();
		}
		return this.getSession().createQuery(hql).list();
	}
	
	

	public Product findById(Long id) {
		Product entity = get(id);
		return entity;
	}

	public Product save(Product bean) {
		getSession().save(bean);
		return bean;
	}

	public Product deleteById(Long id) {
		Product entity = super.get(id);
		if (entity != null) {
			getSession().delete(entity);
		}
		return entity;
	}

	@Override
	protected Class<Product> getEntityClass() {
		return Product.class;
	}
	
	@SuppressWarnings("unchecked")
	public List<Product> getCountProduct(Long webId, Long ctgId) {
		Finder f = Finder.create("select distinct bean from Product bean");
		f.append(" join bean.category node,Category parent");
		if(ctgId!=null){
			f.append(" where node.lft between parent.lft and parent.rgt");
			f.append(" and parent.id=:ctgId");
			f.setParam("ctgId", ctgId);
		}else {
			f.append(" where 1=1 ");
		}
		return find(f);
	}

}